
#include <DFA.h>

DFA::DFA() : valid(1)
{
	name[0] = 0;
	currState = "None";
}

DFA::DFA(char* fname) : valid(1)
{
	strcpy(name, fname);
	final.set(&states);
	currState = "None";
}

DfaType DFA::check(Element elem)
{
	if ( elem == "Sigma" ) return ipTypeSigma;
	if ( elem == "States" ) return ipTypeStates;
	if ( elem == "Start" ) return ipTypeStart;
	if ( elem == "Delta" ) return ipTypeDelta;
	if ( elem == "Final" ) return ipTypeFinal;
	return ipTypeNone;
}

int DFA::readTransitions(ifstream& ifs)
{
	int symbolsRead = 0;
	char buffer[256], c;

	delta.create(states.numElements());

	while ( ifs.get(buffer, 255) ) {
		ifs.get(c);
		Tokens tokens(buffer);
		TokensIter ti(tokens);

		// check for end of transition table
		if ( ti.current()->element == "." ) return 1;

		if ( !symbolsRead ) {
			symbolsRead = 1;
			ti++; // skip the first token
			for ( ; ti.ok(); ti++ ) {
				if ( !sigma.ifExists(ti.current()->element) ) {
					cerr << "Warning : "
						<< "Symbol '" << ti.current()->element
						<< "' not in the set of valid input symbols"
						<< endl;
				}
			} // for
		} else {
			// read transitions
			if ( !states.ifExists(ti.current()->element) ) {
				cerr << "Warning : "
					<< "State '" << ti.current()->element
					<< "' not in the set of valid states"
					<< endl;
			} else {
				Element tempElem = ti.current()->element;
				StoreIter si(sigma);	
				ti++;
				for ( ; ti.ok(); ti++ ) {
					if ( !states.ifExists(ti.current()->element) ) {
						cerr << "Warning : "
							<< "State '" << ti.current()->element
							<< "' not in the set of valid states"
							<< endl;
					} else {
						if ( si.ok() ) {
							delta.add(tempElem,
								si.current()->element,
								ti.current()->element);
							si++;
						} // if si.ok()
					} // else
				} // for ti.ok
			} // else
		} // else
	} // while

	return 0;
}

void DFA::readFile(char* fname)
{
	char buffer[256], c;

	strcpy(name, fname);

	ifstream ifs(fname);
	while ( ifs.get(buffer, 255) ) {
		ifs.get(c);
		Tokens tokens(buffer);
		TokensIter ti(tokens);
		switch ( check(ti.current()->element) ) {
			case ipTypeSigma :
				ti++;
				if ( ti.ok() )
					sigma.read(ti);
				else
					cerr << "Warning : "
						<< "Set of input symbols not specified"
						<< endl;
				break;
			case ipTypeStates :
				ti++;
				if ( ti.ok() )
					states.read(ti);
				else
					cerr << "Warning : "
						<< "Set of states not specified" << endl;
				break;
			case ipTypeStart :
				ti++;
				if ( ti.ok() )
					start = Element(ti.current()->element);
				else
					cerr << "Warning : "
						<< "Start state not specified" << endl;
				break;
			case ipTypeDelta :
				if ( !readTransitions(ifs) )
					cerr << "Warning : "
						<< "State transitions not specified"
						<< endl;
				break;
			case ipTypeFinal :
				ti++;
				if ( ti.ok() )
					final.read(ti);
				else
					cerr << "Warning : "
						<< "Set of final state(s) not specified"
						<< endl;
				break;
		}
	}
}

void DFA::read()
{
	readFile(name);
}

void DFA::read(char* fname)
{
	readFile(fname);
}

void DFA::reset()
{
	currState = start;
}

int DFA::doTransition(char input)
{
	char temp[5];
	temp[0] = input; temp[1] = 0;
	Element tempElem(temp);
	if ( !sigma.ifExists(tempElem) ) {
		cerr << "Warning : " << "Input Symbol '"
			<< tempElem << "' not valid" << endl;
	} else {
		currState = delta.getLink(currState, tempElem);
		return 1;
	}
	return 0;
}

void DFA::run()
{
	char temp;
	cin >> temp;
	if ( valid )
		if ( !doTransition(temp) )
			valid = 0;
}

void DFA::run(char* input)
{
	if ( input ) {
		currState = start;
		for ( int i = 0; input[i]; i++ )
			if ( !doTransition(input[i]) )
				valid = 0;
	}
}

Element DFA::state()
{
	return currState;
}

int DFA::accepted()
{
	if ( !valid ) return -1;
	return final.ifExists(currState);
}

DFA::~DFA()
{
	//delete delta;
}

ostream& operator<<(ostream& os, const DFA& dfa)
{
	os << "Sigma = " << dfa.sigma << endl;
	os << "States = " << dfa.states << endl;
	os << "Start = " << dfa.start << endl;
	os << "Delta = " << endl << dfa.delta;
	os << "Final = " << dfa.final << endl;
	return os;
}

